package com.yst.sqlbuilder;

import com.yst.lambda.TableFieldFunc;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.*;
import java.util.stream.Collectors;

public class SQLGroupBy<T> implements ISQLExpression, IParentedSelect<T> {

    private final Set<SQLField<T>> groupByFieldList=new HashSet<>();

    private final SQLSelect<T> sqlParentSelect;
    public SQLGroupBy(SQLSelect<T> sqlParentSelect){
        this.sqlParentSelect =sqlParentSelect;
    }

    @SafeVarargs
    public final SQLGroupBy<T> groupBy(TableFieldFunc<T, ?>... field){
        groupByFieldList.addAll(Arrays.stream(field).map((it)->new SQLField<>(it,sqlParentSelect)).collect(Collectors.toList()));
        return this;
    }

    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    static class HavingItem<T> implements ISQLExpression{
        private SQLAggField<T> havingField;
        private Symbol havingSymbol;
        private Object havingValue;
        @Override
        public String generateExpression(GenerateParam param) {
            if (havingValue instanceof Number){
                return havingField.generateExpression(
                        param
                ).concat(havingSymbol.symbol).concat(havingValue.toString());
            }
            return havingField.generateExpression(param)
                    .concat(havingSymbol.symbol)
                    .concat(String.format("'%s'",havingValue.toString()));
        }
    }

    private final List<ISQLExpression> havingItems=new ArrayList<>();
    public SQLGroupBy<T> having(SQLAggField<T> field, Symbol symbol,Object value){
        this.havingItems.add(new HavingItem<>(new SQLAggField<>(this.sqlParentSelect,
                field.getFuncField(),field.getAggregation()),symbol,value));
        return this;
    }
    public SQLGroupBy<T> having(SQLExpGroup<T,?> expressionGroup){
        this.havingItems.add(expressionGroup);
        return this;
    }

    @Override
    public String generateExpression(GenerateParam param) {
        if (groupByFieldList.isEmpty()) return "";
        String result="";
        result="GROUP BY".concat(" ")
                .concat(groupByFieldList.stream().map(it->it.generateExpression(param)).collect(Collectors.joining(",")));
        if (!havingItems.isEmpty()){
            result=result.concat("\r\n").concat("HAVING(").concat(
                    havingItems.stream().map(it->it.generateExpression(param))
                            .collect(Collectors.joining(" AND "))
            ).concat(")");
        }
        return result;
    }

    @Override
    public SQLSelect<T> getParentSelect() {
        return sqlParentSelect;
    }
}
